package com.netty.esc.service.action;

import com.alibaba.fastjson.JSONObject;
import com.netty.esc.utils.ClassUtil;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.ApplicationObjectSupport;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author PHY
 * 函数注册中心
 * @date 2023/2/8$-14:08
 */
@Slf4j
public class ApplicationEventCenter extends ApplicationObjectSupport {
    //存储函数执行器
    public static ConcurrentHashMap<String, ActionProcessor> processors = new ConcurrentHashMap<>();

    private ApplicationEventCenter() {
    }
    private static class ActionCenterHolder {
        private static final ApplicationEventCenter INSTANCE = new ApplicationEventCenter();
    }

    public static ApplicationEventCenter getInstance() {
        return ApplicationEventCenter.ActionCenterHolder.INSTANCE;
    }

    public void init(){
        this.registerProcessUnit();
    }

    /**
     * 注册函数执行单元
     */
    private void registerProcessUnit() {
        try {
            List<Class<?>> allActionClass = ClassUtil.getAllAssignedClass(BaseAction.class);
            for (Class<?> actionClass : allActionClass) {
                Method[] methods = actionClass.getDeclaredMethods();
                for (Method method : methods) {
                    //判断方法是否符合执行标准
                    if (isExecutable(method)) {
                        ActionType annotation = method.getAnnotation(ActionType.class);
                        if (annotation != null) {
                            ActionProcessor processor = new ActionProcessor(actionClass, method);
                            processors.put(annotation.value().code(), processor);
                        }
                    }
                }

            }
        } catch (Throwable throwable) {
            log.error("方法执行单元注册失败", throwable);
        }
    }

    /**
     * 判断函数可执行
     *
     * @param method 要注册的方法
     * @return true
     */
    private boolean isExecutable(Method method) {
        int modifiers = method.getModifiers();
        Class<?>[] params = method.getParameterTypes();
        return method.isAnnotationPresent(ActionType.class)
                && params.length == 2
                && params[0] == ChannelHandlerContext.class
                && params[1] == JSONObject.class
                && Modifier.isPublic(modifiers);
    }
}
